package com.powergisol.gis.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.powergisol.gis.entity.*;
import com.powergisol.gis.service.SaveDataService;
import com.powergisol.gis.util.XyChangeUtil;
import com.powergisol.gis.vo.*;
import javafx.scene.control.Tab;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Description:excel读取监听器
 */
public class ExcelPTListener extends AnalysisEventListener {

    TabExcelVo vo;

    CacheManager cacheManager;

    TabCoordinateSystem system;

    Integer userId;

    public ExcelPTListener() {
    }

    public ExcelPTListener(TabExcelVo vo,
                           CacheManager cacheManager, TabCoordinateSystem system,Integer userId) {
        this.vo = vo;
        this.cacheManager = cacheManager;
        this.system = system;
        this.userId = userId;
    }

    /**
     * 每隔1000条存储数据库，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 1000;

    List<Object> list = new ArrayList<>();

    int i = 0;//循环次数

    int listSize = 0;//总的条数

    ArrayList titleData;


    @Override
    public void invoke(Object o, AnalysisContext analysisContext) {
        if(null != vo.getReadRows()){
            if(listSize<=vo.getReadRows()-1){
                list.add(o);
                if (list.size() >= BATCH_COUNT) {
                    i = i + 1;
                    saveData();
                    list.clear();
                }
            }
        }else{
            list.add(o);
            if (list.size() >= BATCH_COUNT) {
                i = i + 1;
                saveData();
                list.clear();
            }
        }
        if(vo.getTitleRows()-1 == listSize){
            titleData = (ArrayList) o;
        }
        listSize = listSize +1;
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        i = i + 1;
        saveData();
        System.out.println("解析完成");
    }

    /**
     * 加上存储数据库
     */
    public void saveData() {
        List<TabBaseExcel> listBase = new ArrayList<>();//存放基础数据
        List<TabExcelDetail> listDetail = new ArrayList<>();//存放详情的数据
        List<ExcelInFailedDataVo> listFailed = new ArrayList<>();//失败数据
        String cellValue = null;
        Integer startRows = 0;//开始行数
        Integer rowNums = 1;
        if (i == 1) {
            startRows = vo.getStartRows();
            rowNums = vo.getStartRows();
        } else {
            startRows = 1;
            rowNums = (i-1) * BATCH_COUNT + 1;
        }
        for (int rowNum = startRows-1; rowNum < list.size(); rowNum++) {
            String uuid = UUID.randomUUID().toString();
            ExcelInFailedDataVo failedDataVo = new ExcelInFailedDataVo();
            TabBaseExcel baseExcel = new TabBaseExcel();
            baseExcel.setUserId(userId);
            baseExcel.setFlagValue(uuid);
            baseExcel.setUuid(vo.getUuid());
            Object rowData = list.get(rowNum);
            ArrayList datas = (ArrayList) rowData;
            BigDecimal x = null;
            BigDecimal y = null;
            for (int colNum = 0; colNum < datas.size(); colNum++) {
                cellValue = String.valueOf(datas.get(colNum));
                //判断值是否为空
                boolean flag = (null == cellValue || ("").equals(cellValue)||("null").equals(cellValue));
//                if (null == cellValue || ("").equals(cellValue)||("null").equals(cellValue)) {
//                    continue;
//                }
                if (!flag && null != vo.getLon() && colNum + 1 == vo.getLon()) {
                    if(!isNumber(cellValue)){
                        failedDataVo.setReason(titleData.get(colNum)+"需为数字");
                        break;
                    }
                    x = new BigDecimal(cellValue);
                    continue;
                }
                if (!flag && null != vo.getLat() && colNum + 1 == vo.getLat()) {
                    if(!isNumber(cellValue)){
                        failedDataVo.setReason(titleData.get(colNum)+"需为数字");
                        break;
                    }
                    y = new BigDecimal(cellValue);
                    continue;
                }
                if (!flag && null != vo.getHeight() && colNum + 1 == vo.getHeight()) {
                    if(!isNumber(cellValue)){
                        failedDataVo.setReason(titleData.get(colNum)+"需为数字");
                        break;
                    }
                    baseExcel.setHeight(new Double(cellValue));
                    continue;
                }
                if (!flag && null != vo.getMc() && colNum + 1 == vo.getMc()) {
                    baseExcel.setMc(cellValue);
                    continue;
                }

                if (null != x && null != y) {
                    BigDecimal lat = BigDecimal.ZERO;
                    BigDecimal lon = BigDecimal.ZERO;
                    if(1 == vo.getIsChange()){
                        lat = XyChangeUtil.change(x.doubleValue(), y.doubleValue(),system.getCoorChangeLat());
                        lon = XyChangeUtil.change(x.doubleValue(), y.doubleValue(),system.getCoorChangeLon());
                    }else{
                        lat = y;//纬度-90->90
                        lon = x;//经度-180->180
                    }
                    if (lon.compareTo(new BigDecimal("180")) > 0 || lon.compareTo(new BigDecimal("-180")) < 0 ||
                            lat.compareTo(new BigDecimal("90")) > 0 || lat.compareTo(new BigDecimal("-90")) < 0) {
                        failedDataVo.setReason("x或y坐标系不在范围内");
                      //  listFailed.add(failedDataVo);
                      //  rowNums++;
                        break;
                    }
                    baseExcel.setLon(lon.doubleValue());
                    baseExcel.setLat(lat.doubleValue());
                }
                if(null !=vo.getDetails() && vo.getDetails().size()>0){
                    List<DetailVo> vos = vo.getDetails();
                    for (DetailVo detailVo:vos) {
                        if(detailVo.getMouldCol() == colNum+1){
                            TabExcelDetail excelDetail = new TabExcelDetail();
                            excelDetail.setUuid(vo.getUuid());
                            excelDetail.setFlagValue(uuid);
                            excelDetail.setColumnName(detailVo.getMouldKey());
                            excelDetail.setColumnValue(cellValue);
                            listDetail.add(excelDetail);
                            break;
                        }
                    }
                }
            }
            if(null != baseExcel.getLat() && null != baseExcel.getLon()){
                listBase.add(baseExcel);
            }
            rowNums++;
        }
        Cache cache = cacheManager.getCache("cache-data");
        if(null != cache.get(vo.getUuid()+"result")){
            ExcelBaseResultVo resultVo = cache.get(vo.getUuid()+"result",ExcelBaseResultVo.class);
            List<ExcelInFailedDataVo> list = resultVo.getListFailed();
            list.addAll(listFailed);
            resultVo.setListFailed(list);

            List<TabBaseExcel> listBase1 = resultVo.getListBase();
            listBase1.addAll(listBase);
            resultVo.setListBase(listBase1);

            List<TabExcelDetail> listDetail1 = resultVo.getListDetail();
            listDetail1.addAll(listDetail);
            resultVo.setListDetail(listDetail1);

            cache.put(vo.getUuid()+"result",resultVo);
        }else{
            ExcelBaseResultVo resultVo = new ExcelBaseResultVo();
            resultVo.setListFailed(listFailed);
            resultVo.setListBase(listBase);
            resultVo.setListDetail(listDetail);
            cache.put(vo.getUuid()+"result",resultVo);
        }
    }

    private boolean isNumber(String value) {
        if(null == value){
            return false;
        }
        String matchStr = "^[-\\+]?(\\d+|\\d+\\.\\d+)$";
        return value.matches(matchStr);
    }


}
